// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Microsoft.VSPowerToys.VSCmdShell
{
	/// <summary>
	/// Circular command history that can also filter entries based on a prefix
	/// </summary>
    [Serializable]
   	public class CommandHistoryCollection : WrappingCollection<string>
    {

        #region Private Members

        private string prefix;

        #endregion

        #region Public Properties

        /// <summary>
        /// Prefix to filter history entries. Only the entries starting
        /// with this prefix will be presented to user.
        /// </summary>
        /// <remarks>If null filtering will be disabled</remarks>
        public string Prefix
        {
            set
            {
                this.prefix = value;
            }
            get
            {
                return this.prefix;
            }
        }

        /// <summary>
        /// Gets the next element on the list.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException">Throws IndexOutOfRangeException if list is empty</exception>
        public new string Next
        {
            get
            {
                if (this.Count == 0)
                {
                    return String.Empty;
                }
                string returnValue = this.CurrentNode.Value;
                if (this.Count > 1 && this.CurrentNode != this.Last)
                {
                    this.CurrentNode = this.CurrentNode.Next;
                }
                return returnValue;
            }
        }

        /// <summary>
        /// Gets the previous element on the list.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException">Throws IndexOutOfRangeException if list is empty</exception>
        public new string Previous
        {
            get
            {
                if (this.Count == 0)
                {
                    return String.Empty;
                }
                if (this.Count > 1 && this.CurrentNode != this.First)
                {
                    this.CurrentNode = this.CurrentNode.Previous;
                }
                return this.CurrentNode.Value;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public CommandHistoryCollection()
            : base()
        {
        }

        /// <summary>
        /// Constructor required for implementing ISerializable
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected CommandHistoryCollection(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
        
        #endregion

        /// <summary>
        /// Resets the position of the list and also the prefix value
        /// </summary>
        public void ResetList()
        {
            this.ResetPosition();
            this.prefix = null;
        }

        /// <summary>
        /// Gets the next or previous history entry that matches to prefix.
        /// </summary>
        /// <param name="getNext">If true the next entry will be retrieved, if false the
        /// previous entry will be retrieved</param>
        /// <returns>a command user typed before</returns>
        public string GetHistoryEntry(bool getNext)
        {
            if (this.Count == 0)
            {
                return String.Empty;
            }
            LinkedListNode<string> prevNode = this.CurrentNode;
            do
            {
                prevNode = this.CurrentNode;
                string current = getNext ? this.Next : this.Previous;
                if (this.prefix == null || current.StartsWith(this.prefix))
                {
                    return current;
                }
            } while (prevNode != this.CurrentNode);
            return String.Empty;
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
        }
        

	

	}
}
